package com.starsoft.frame.fileimport;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.starsoft.frame.fileimport.pojo.Column;
import com.starsoft.frame.fileimport.pojo.DataTable;
import com.starsoft.frame.fileimport.pojo.NullType;
import com.starsoft.frame.fileimport.pojo.Table;
import com.starsoft.frame.fileimport.pojo.ValueType;
import com.starsoft.frame.fileimport.pojo.Table.TitleType;
import com.starsoft.frame.util.StringUtil;

public class ExcelReader extends FileReaderImpl {
	
	private static Logger logger = LoggerFactory.getLogger(ExcelReader.class);
	
	public final static String EXCEL2003 = "EXCEL2003";
	public final static String EXCEL2010 = "EXCEL2010";

	private String excelVersion = EXCEL2010;
	private boolean transpose = false;

	public ExcelReader() {

	}
	
	public ExcelReader(String excelVersion, boolean transpose) {
		this.excelVersion = excelVersion;
		this.transpose = transpose;
	}

	@Override
	public DataTable read(InputStream source, Table table) {
		DataTable dataTable = new DataTable();
		dataTable.setTable(table);
		Sheet sheet = getSheet(source, table.getSheetIndex());
		Cell[][] cellArray = getCellArray(sheet, table);
		
		readTitle(cellArray, table);
		dataTable.setData(readData(cellArray, table));
		return dataTable;
	}
	
	private Cell[][] getCellArray(Sheet sheet, Table table){
		if (table.getEndRow() < 0) {
			table.setEndRow(sheet.getPhysicalNumberOfRows());
		}
		if (table.getEndCol() < 0) {
			table.setEndCol(sheet.getRow(0).getPhysicalNumberOfCells());
		}

		Cell[][] cellArray = new Cell[table.getEndRow()][table.getEndCol()];
		for (int i = 0; i < table.getEndRow(); i++) {
			Row row = sheet.getRow(i);
			for (int j = 0; j < table.getEndCol(); j++) {
				cellArray[i][j] = row.getCell(j);
			}
		}
		if (transpose) {
			Cell[][] transposeCellArray = new Cell[table.getEndCol()][table.getEndRow()];
			for (int i = 0; i < table.getEndRow(); i++) {
				for (int j = 0; j < table.getEndCol(); j++) {
					transposeCellArray[j][i] = cellArray[i][j];
				}
			}
			cellArray = transposeCellArray;
			table.setEndRow(cellArray.length);
			table.setEndCol(cellArray[0].length);
		}
		
		return cellArray;
	}

	private List<Map<String, Object>> readData(Cell[][] cellArray, Table table) {
		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();

		int rowNum = table.getRowNum();
		List<Column> columnList = table.getColumnList();
		for (int i = 0; i < rowNum; i++) {
			Map<String, Object> rowMap = new HashMap<String, Object>();
			Cell[] row = cellArray[i + table.getStartRow()];
			for (Column column : columnList) {
				if(column.getColIndex()==null){
					continue;
				}
				Cell cell = row[column.getColIndex()];
				String value = null;
				if (cell != null) {
					if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
						value = cell.getNumericCellValue() + "";
					} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
						value = cell.getBooleanCellValue() + "";
					} else {
						value = cell.getStringCellValue();
					}
				}

				Object ob = str2Obj(value, column.getValueType(), column.getFormat());
				if (ob == null && column.getNullType() == NullType.nullable) {
					ob = column.getDefaultValue();
				} else if (ob == null && column.getNullType() != NullType.nullable) {
					throw new RuntimeException((i + table.getStartRow() + 1) + " row:" + column.getName()
							+ " can not be null");
				}
				rowMap.put(column.getMapKey(), ob);
			}
			data.add(rowMap);
		}
		return data;
	}

	private void readTitle(Cell[][] cellArray, Table table) {
		int colNum = table.getEndCol();
		String[] names = new String[colNum];
		String[] codes = new String[colNum];
		ValueType[] types = new ValueType[colNum];
		NullType[] nullTypes = new NullType[colNum];
		Object[] defaults = new Object[colNum];
		Integer[] colIndex = new Integer[colNum];

		if (table.getNameRow() >= 0) {
			Cell[] row = cellArray[table.getNameRow()];
			for (int i = 0; i < colNum; i++) {
				names[i] = row[i + table.getStartCol()].getStringCellValue();
				colIndex[i]=i + table.getStartCol();
			}
		}
		if (table.getCodeRow() >= 0) {
			Cell[] row = cellArray[table.getCodeRow()];
			for (int i = 0; i < colNum; i++) {
				colIndex[i]=i + table.getStartCol();
				String typestr = null;
				Cell cell = row[i + table.getStartCol()];
				if (cell != null) {
					typestr = cell.getStringCellValue();
				}
				String[] values = StringUtil.split2Array(typestr, "/");
				if (values.length > 0) {
					codes[i] = values[0];
				}
				if (values.length > 1) {
					types[i] = ValueType.toEnum(values[1]);
				}
				if (values.length > 2) {
					nullTypes[i] = NullType.toEnum(values[2]);
				}
				if (values.length > 3) {
					defaults[i] = str2Obj(values[3], types[i]);
				}
			}
		}
		List<Column> columnList = table.getColumnList();
		if (columnList == null) {
			columnList = new ArrayList<Column>();
			for (int i = 0; i < colNum; i++) {
				Column column = new Column(colIndex[i], codes[i], names[i], types[i], nullTypes[i],
						defaults[i]);
				columnList.add(column);
			}
			table.setColumnList(columnList);
		} else {
			for (int i = 0; i < colNum; i++) {
				Column column;
				if (TitleType.OnlyName.equals(table.getTitleType())) {
					column = table.getColumnByName(names[i]);
				} else {
					column = table.getColumnByCode(codes[i]);
				}
				if (column != null) {
					column.updateIf(colIndex[i], codes[i], names[i], types[i], nullTypes[i],
							defaults[i]);
				} else {
					logger.debug("{} not list in table", codes[i]);
				}
			}
			for (Column column : columnList) {
				if(column.getColIndex()==null){
				 	logger.warn("{} no value in input", column.getCode());
				}
			}
		}
	}

	@SuppressWarnings("resource")
	private Sheet getSheet(InputStream source, int sheetIndex) {
		Workbook workbook = null;
		try {
			if (excelVersion.equals(EXCEL2003)) {
				workbook = new HSSFWorkbook(source);
			} else {
				workbook = new XSSFWorkbook(source);
			}
			return workbook.getSheetAt(sheetIndex);

		} catch (Exception e) {
			throw new RuntimeException("get sheet error:"+e.getMessage());
		}
	}

	public String getExcelVersion() {
		return excelVersion;
	}

	public void setExcelVersion(String excelVersion) {
		this.excelVersion = excelVersion;
	}

	@Override
	public DataTable read(String content, Table table) {
		throw new RuntimeException("not suppourt");
	}

}
